home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gr2ps / gr2ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-05  |  25.2 KB  |  1,085 lines

  1. /*
  2.  *  gr2ps - convert a gremlin file into a PostScript printer
  3.  *  language file, which can be printed to printers which
  4.  *  support PostScript (like the Apple LaserWriter).
  5.  *
  6.  *  (c) 1986 John Coker
  7.  *  University of California, Berkeley
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include <math.h>
  13. #include <varargs.h>
  14.  
  15. #define isinteger(c)    (isdigit(c) || (c) == '-')
  16. #define isfloat(c)    (isdigit(c) || (c) == '.' || (c) == '-')
  17.  
  18. char    *program;
  19. char    USAGE[] = "usage: %s [ -n ] [ -R font ] [ -I font ] [ -B font ] [ -S font ] [ -s X Y ] [ -t X Y ] [ -p X Y ] [ -o file ] [ file ]\n";
  20. char    *errfile = NULL;
  21. int    errline = -1;
  22.  
  23. int    setscale = 0;
  24. double    gscaleX = 1.0, gscaleY = 1.0;
  25. int    settrans = 0;
  26. double    gtransX = 0.0, gtransY = 0.0;
  27. int    setplace = 0;
  28. double    gplaceX = 0.0, gplaceY = 0.0;
  29. int    newformat = 0;
  30.  
  31. char    *R_fontname = "Times-Roman";
  32. char    *I_fontname = "Times-Italic";
  33. char    *B_fontname = "Times-Bold";
  34. char    *S_fontname = "Courier-Bold";
  35.  
  36. main(argc, argv)
  37.     char    *argv[];
  38. {
  39.     extern char    *rindex();
  40.     extern double    atof();
  41.     register char    *ap;
  42.     char        *outputfile = NULL;
  43.     FILE        *input, *output;
  44.     int        status;
  45.  
  46.     program = rindex(*argv, '/');
  47.     if (program == NULL)
  48.         program = *argv;
  49.     else
  50.         program++;
  51.  
  52.     /* process command line options */
  53.     while (--argc > 0 && **++argv == '-') {
  54.         if (*(*argv+1) == '\0')
  55.             break;
  56.         for (ap = ++*argv; *ap != '\0'; ap++)
  57.             switch (*ap) {
  58.             case 'B':    /* bold font name */
  59.                 if (--argc < 1 || *++argv == NULL) {
  60.                     fprintf(stderr, USAGE, program);
  61.                     exit(1);
  62.                 }
  63.                 B_fontname = *argv;
  64.                 break;
  65.             case 'I':    /* italic font name */
  66.                 if (--argc < 1 || *++argv == NULL) {
  67.                     fprintf(stderr, USAGE, program);
  68.                     exit(1);
  69.                 }
  70.                 I_fontname = *argv;
  71.                 break;
  72.             case 'R':    /* roman font name */
  73.                 if (--argc < 1 || *++argv == NULL) {
  74.                     fprintf(stderr, USAGE, program);
  75.                     exit(1);
  76.                 }
  77.                 R_fontname = *argv;
  78.                 break;
  79.             case 'S':    /* special font name */
  80.                 if (--argc < 1 || *++argv == NULL) {
  81.                     fprintf(stderr, USAGE, program);
  82.                     exit(1);
  83.                 }
  84.                 S_fontname = *argv;
  85.                 break;
  86.             case 'n':    /* newer file format */
  87.                 newformat = 1;
  88.                 break;
  89.             case 'o':    /* specity output file */
  90.                 if (--argc < 1 || *++argv == NULL) {
  91.                     fprintf(stderr, USAGE, program);
  92.                     exit(1);
  93.                 }
  94.                 outputfile = *argv;
  95.                 break;
  96.             case 'p':    /* place at this position */
  97.                 if (argc < 3 || !isfloat(argv[1][0]) ||
  98.                     !isfloat(argv[2][0])) {
  99.                     fprintf(stderr, USAGE, program);
  100.                     exit(1);
  101.                 }
  102.                 gplaceX = atof(argv[1]);
  103.                 gplaceY = atof(argv[2]);
  104.                 argc -= 2;
  105.                 argv += 2;
  106.                 setplace = 1;
  107.                 break;
  108.             case 's':    /* specify global scale */
  109.                 if (argc < 3 || !isfloat(argv[1][0]) ||
  110.                     !isfloat(argv[2][0])) {
  111.                     fprintf(stderr, USAGE, program);
  112.                     exit(1);
  113.                 }
  114.                 gscaleX = atof(argv[1]);
  115.                 gscaleY = atof(argv[2]);
  116.                 argc -= 2;
  117.                 argv += 2;
  118.                 setscale = 1;
  119.                 break;
  120.             case 't':    /* specify global translation */
  121.                 if (argc < 3 || !isfloat(argv[1][0]) ||
  122.                     !isfloat(argv[2][0])) {
  123.                     fprintf(stderr, USAGE, program);
  124.                     exit(1);
  125.                 }
  126.                 gtransX = atof(argv[1]);
  127.                 gtransY = atof(argv[2]);
  128.                 argc -= 2;
  129.                 argv += 2;
  130.                 settrans = 1;
  131.                 break;
  132.             default:    /* bad option */
  133.                 fprintf(stderr, USAGE, program);
  134.                 exit(1);
  135.             }
  136.     }
  137.     if (settrans && setplace) {
  138.         fprintf(stderr, "%s: Only one of -t and -p, please.\n",
  139.             program);
  140.         exit(1);
  141.     }
  142.  
  143.     /* open output file */
  144.     if (outputfile == NULL || *outputfile == '\0') {
  145.         /* use standard output */
  146.         output = stdout;
  147.     } else if ((output = fopen(outputfile, "w")) == NULL) {
  148.         fprintf(stderr, "%s: Can't open output file ", program);
  149.         perror(outputfile);
  150.         exit(1);
  151.     }
  152.  
  153.     /* read and translate given gremlin files */
  154.     if (argc > 0) {
  155.         /* loop over argument file names */
  156.         status = 0;
  157.         while (argc-- > 0) {
  158.             if (**argv == '\0' || !strcmp(*argv, "-")) {
  159.                 /* read standard input at this point */
  160.                 errline = 0;
  161.                 errfile = "(stdin)";
  162.                 status += grn_to_ps(input, output) != 0;
  163.             } else if ((input = fopen(*argv, "r")) == NULL) {
  164.                 fprintf(stderr, "%s: Can't open ", program);
  165.                 perror(*argv);
  166.                 status++;
  167.             } else {
  168.                 errline = 0;
  169.                 errfile = *argv;
  170.                 status += grn_to_ps(input, output) != 0;
  171.                 fclose(input);
  172.             }
  173.             argv++;
  174.         }
  175.     } else {
  176.         /* process standard input */
  177.         errline = 0;
  178.         errfile = "(stdin)";
  179.         status = grn_to_ps(stdin, output) != 0;
  180.     }
  181.  
  182.     if (output != stdout)
  183.         fclose(output);
  184.  
  185.     exit(0);
  186. }
  187.  
  188. char    OLDFIRSTLINE[] = "gremlinfile\n";
  189. char    NEWFIRSTLINE[] = "sungremlinfile\n";
  190. int    LASTELEMENT = -1;
  191.  
  192. static char    *element_names[] = {
  193.     "BOTLEFT",        /* bottom left text - 0 */
  194.     "BOTRIGHT",        /* bottom right text - 1 */
  195.     "CENTCENT",        /* center text - 2 */
  196.     "VECTOR",        /* vector - 3 */
  197.     "ARC",            /* arc - 4 */
  198.     "CURVE",        /* curve - 5 */
  199.     "POLYGON",        /* polygon - 6 */
  200.     "CURVE BSPLINE",    /* b-spline - 7 */
  201.     "CURVE BEZIER",        /* bezier spline - 8 */
  202.     NULL,
  203.     "TOPLEFT",        /* top left text - 10 */
  204.     "TOPCENT",        /* top center text - 11 */
  205.     "TOPRIGHT",        /* top right text - 12 */
  206.     "CENTLEFT",        /* left center text - 13 */
  207.     "CENTRIGHT",        /* right center text - 14 */
  208.     "BOTCENT",        /* bottom center text - 15 */
  209. };
  210. static int    element_count = sizeof (element_names) / sizeof (char *);
  211.  
  212. struct point {
  213.     double        p_x,
  214.             p_y;
  215. };
  216.  
  217. struct element {
  218.     short        e_what;        /* what type of element */
  219.     short        e_ptcnt;    /* number of points */
  220.     struct point    *e_points;    /* list of points */
  221.     short        e_brush;    /* brush style */
  222.     short        e_size;        /* text size */
  223.     char        *e_text;    /* text string */
  224.     double        e_llx,        /* lower-left X */
  225.             e_lly,        /* lower-left Y */
  226.             e_urx,        /* upper-right X */
  227.             e_ury;        /* upper-right Y */
  228. };
  229.  
  230. #define MAXPOINTS    500    /* maximum points per element */
  231. #define MAXELEMENTS    5000    /* maximum elements per file */
  232.  
  233. #define TOP        1    /* top oriented text */
  234. #define BOTTOM        2    /* bottom oriented text */
  235. #define LEFT        3    /* left justified text */
  236. #define CENTER        4    /* centered text */
  237. #define RIGHT        5    /* right justified text */
  238.  
  239. #define LARGE    1000000        /* initial value for max/min pairs */
  240.  
  241. /* these should be local variables, but ... */
  242. static struct element    elt_list[MAXELEMENTS];
  243. static struct point    point_list[MAXPOINTS];
  244.  
  245. grn_to_ps(input, output)
  246.     FILE    *input, *output;
  247. {
  248.     extern double    atof();
  249.     extern char    *malloc(), *savestr();
  250.     char        lbuf[1024];
  251.     register char    *lp, *ep;
  252.     struct point    *point_end = point_list + MAXPOINTS;
  253.     struct point    *ptp, *ptend;
  254.     struct element    *elt_end = elt_list + MAXELEMENTS;
  255.     struct element    *elt, *elend;
  256.     register int    e, t, len;
  257.     double        llx, lly, urx, ury;
  258.  
  259.     /* check validity of this file */
  260.     if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  261.         error("Input file is empty!");
  262.         return (-1);
  263.     }
  264.     errline = 1;
  265.     if (strcmp(lbuf, NEWFIRSTLINE) == 0) {
  266.         /* this is new format, at least */
  267.         newformat = 1;
  268.     } else if (strcmp(lbuf, OLDFIRSTLINE) != 0) {
  269.         error("Input file not produced by gremlin!");
  270.         return (-1);
  271.     }
  272.  
  273.     /* get orientation/positioning line */
  274.     if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  275.         error("Input file is too short (missing orientation).");
  276.         return (-1);
  277.     }
  278.     errline++;
  279.  
  280.     /* initialize bounding box values */
  281.     llx = lly = LARGE;
  282.     urx = ury = -LARGE;
  283.  
  284.     /* look through file reading picture elements */
  285.     elt = elt_list;
  286.     while (fgets(lbuf, sizeof (lbuf), input) != NULL && elt < elt_end) {
  287.         errline++;
  288.         /* read in this element specification */
  289.         for (lp = lbuf; isspace(*lp); lp++)
  290.             ;
  291.         if (newformat && !isinteger(*lp)) {
  292.             for (ep = lp; *ep != '\0' && *ep != '\n'; ep++)
  293.                 ;
  294.             do
  295.                 *ep-- = '\0';
  296.             while (ep > lp && isspace(*ep));
  297.             if (ep <= lp) {
  298.                 error("Missing element name!");
  299.                 return (-1);
  300.             }
  301.             for (e = 0; e < element_count; e++)
  302.                 if (element_names[e] != NULL &&
  303.                     !strcmp(element_names[e], lp))
  304.                     break;
  305.             if (e >= element_count) {
  306.                 error("Unknown element type %s!", lp);
  307.                 return (1);
  308.             }
  309.             elt->e_what = e;
  310.         } else if (isinteger(*lp)) {
  311.             /* old style numeric element type */
  312.             elt->e_what = atoi(lbuf);
  313.         } else {
  314.             error("Bad format for element specification.");
  315.             return (-1);
  316.         }
  317.         if (elt->e_what == LASTELEMENT) {
  318.             /* this is the end-of-list marker */
  319.             break;
  320.         }
  321.  
  322.         /* read in associated point list */
  323.         ptend = point_list;
  324.         while (fgets(lbuf, sizeof (lbuf), input) != NULL &&
  325.                ptend < point_end) {
  326.             errline++;
  327.             /* read in this X and Y coordinate */
  328.             for (lp = lbuf; isspace(*lp); lp++)
  329.                 ;
  330.             if (newformat && *lp == '*')
  331.                 break;
  332.             if (!isfloat(*lp))
  333.                 goto badpoint;
  334.             ptend->p_x = atof(lp);
  335.             while (isfloat(*lp))
  336.                 lp++;
  337.             while (isspace(*lp))
  338.                 lp++;
  339.             if (!isfloat(*lp)) {
  340. badpoint:            error("Bad point specified, need X and Y.");
  341.                 return (-1);
  342.             }
  343.             ptend->p_y = atof(lp);
  344.             if (!newformat &&
  345.                 ptend->p_x < 0.0 && ptend->p_y < 0.0) {
  346.                 /* end of point list */
  347.                 break;
  348.             }
  349.             ptend++;
  350.         }
  351.         if (ptend >= point_end) {
  352.             error("Too many points, maximum is %d!", MAXPOINTS);
  353.             return (-1);
  354.         }
  355.  
  356.         /* read brush and size specification */
  357.         if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  358.             error("File too short (no brush/size entry)!");
  359.             return (-1);
  360.         }
  361.         errline++;
  362.         for (lp = lbuf; isspace(*lp); lp++)
  363.             ;
  364.         if (!isdigit(*lp)) {
  365.             error("Missing brush value for entry!");
  366.             return (-1);
  367.         }
  368.         elt->e_brush = atoi(lp);
  369.         while (isdigit(*lp))
  370.             lp++;
  371.         while (isspace(*lp))
  372.             lp++;
  373.         if (!isdigit(*lp)) {
  374.             error("Missing size value for entry!");
  375.             return (-1);
  376.         }
  377.         elt->e_size = atoi(lp);
  378.  
  379.         /* read count/text specification */
  380.         if (fgets(lbuf, sizeof (lbuf), input) == NULL) {
  381.             error("File too short (missing text entry)!");
  382.             return (-1);
  383.         }
  384.         errline++;
  385.         for (lp = lbuf; isspace(*lp); lp++)
  386.             ;
  387.         if (!isdigit(*lp)) {
  388.             error("Missing text length value in entry!");
  389.             return (-1);
  390.         }
  391.         len = atoi(lp);
  392.         if (len <= 0) {
  393.             /* no text string */
  394.             elt->e_text = NULL;
  395.         } else {
  396.             char    *text;
  397.  
  398.             while (isdigit(*lp))
  399.                 lp++;
  400.             while (isspace(*lp))
  401.                 lp++;
  402.             text = lp;
  403.             for (t = 0; t < len && *lp != '\n'; t++)
  404.                 lp++;
  405.             if (t < len) {
  406. #ifdef NOTDEF
  407.                 error("Text not as long as length given!");
  408. /*
  409.  * There's a bug in gremlin that sometimes gives a bogus text length if
  410.  * the text itself is a string of digits.  But nothing goes wrong if you
  411.  * ignore the given length here.
  412.  */
  413.                 return(1);
  414. #else
  415.                 error("Text not as long as length given, but this is probably okay");
  416. #endif /* NOTDEF */
  417.             }
  418.             *lp = '\0';
  419.             elt->e_text = savestr(text);
  420.         }
  421.  
  422.         /* add this picture element to list */
  423.         elt->e_ptcnt = ptend - point_list;
  424.         if (elt->e_ptcnt > 0) {
  425.             elt->e_points = (struct point *)
  426.                 malloc(elt->e_ptcnt * sizeof (struct point));
  427.             if (elt->e_points == NULL) {
  428.                 fprintf(stderr,
  429.                 "%s: Not enough memory to save %d points!\n",
  430.                     program, elt->e_ptcnt);
  431.                 return (-1);
  432.             }
  433.             bcopy((char *)point_list, (char *)elt->e_points,
  434.                 elt->e_ptcnt * sizeof (struct point));
  435.         }
  436.  
  437.         /* scale and translate the elements */
  438.         if (setscale)
  439.             scale(elt, gscaleX, gscaleY);
  440.         if (settrans)
  441.             translate(elt, gtransX, gtransY);
  442.  
  443.         /* save the bounding box information */
  444.         findbbox(elt);
  445.         if (elt->e_llx < llx)
  446.             llx = elt->e_llx;
  447.         if (elt->e_lly < lly)
  448.             lly = elt->e_lly;
  449.         if (elt->e_urx > urx)
  450.             urx = elt->e_urx;
  451.         if (elt->e_ury > ury)
  452.             ury = elt->e_ury;
  453.  
  454.         /* on to the next element ... */
  455.         elt++;
  456.     }
  457.     elend = elt;
  458.  
  459.     /* handle placing the figure */
  460.     if (setplace) {
  461.         double    dx, dy;
  462.  
  463.         dx = gplaceX - llx;
  464.         dy = gplaceY - lly;
  465.  
  466.         /* move the individual elements */
  467.         for (elt = elt_list; elt < elend; elt++)
  468.             translate(elt, dx, dy);
  469.  
  470.         /* update the entire bounding box */
  471.         llx += dx;
  472.         lly += dy;
  473.         urx += dx;
  474.         ury += dy;
  475.     }
  476.  
  477.     /* output the header comments */
  478.     fprintf(output, "%%!\n");
  479.     fprintf(output, "%%%%Title: %s\n", errfile);
  480.     fprintf(output, "%%%%Creator: %s (Gremlin to PostScript)\n", program);
  481.     fprintf(output, "%%%%BoundingBox: %lg %lg %lg %lg\n",
  482.         llx, lly, urx, ury);
  483.     fprintf(output, "%%%%DocumentFonts: %s %s %s %s\n",
  484.         R_fontname, I_fontname, B_fontname, S_fontname);
  485.     fprintf(output, "%%%%Pages: 1\n");
  486.     fprintf(output, "%%%%EndComments\n\n");
  487.  
  488.     /* output the prologue code */
  489.     fprintf(output, "gsave\n");
  490.     fprintf(output, "%%%%EndProlog\n");
  491.     
  492.     /* Output polygons first, text second and lines last to keep one
  493.        object from covering another as much as possible. */
  494.     for (elt = elt_list; elt < elend; elt++) {
  495.         /* handle this picture element now */
  496.         putc('\n', output);
  497.         switch (elt->e_what) {
  498.         case 6:        /* polygon */
  499.             if (elt->e_ptcnt < 3) {
  500.                 error("Need three or more points in polygon.");
  501.                 return (1);
  502.             }
  503.             polystyle(elt->e_brush, elt->e_size, output);
  504.             makepolygon(elt->e_ptcnt, elt->e_points, output,
  505.                     elt->e_brush, elt->e_size);
  506.             break;
  507.         }
  508.         if (elt->e_what > 15) {
  509.             error("Bad element type %d; ignored.", elt->e_what);
  510.         }
  511.     }
  512.     for (elt = elt_list; elt < elend; elt++) {
  513.         /* handle this picture element now */
  514.         putc('\n', output);
  515.         switch (elt->e_what) {
  516.         case 0:        /* bottom-left justified text */
  517.             textstyle(elt->e_brush, elt->e_size, output);
  518.             textpoint(elt->e_ptcnt, elt->e_points, output);
  519.             textadjust(elt->e_text, BOTTOM, LEFT, output);
  520.             break;
  521.         case 1:        /* bottom-right justified text */
  522.             textstyle(elt->e_brush, elt->e_size, output);
  523.             textpoint(elt->e_ptcnt, elt->e_points, output);
  524.             textadjust(elt->e_text, BOTTOM, RIGHT, output);
  525.             break;
  526.         case 2:        /* center justified text */
  527.             textstyle(elt->e_brush, elt->e_size, output);
  528.             textpoint(elt->e_ptcnt, elt->e_points, output);
  529.             textadjust(elt->e_text, CENTER, CENTER, output);
  530.             break;
  531.         case 10:    /* top-left justified text */
  532.             textstyle(elt->e_brush, elt->e_size, output);
  533.             textpoint(elt->e_ptcnt, elt->e_points, output);
  534.             textadjust(elt->e_text, TOP, LEFT, output);
  535.             break;
  536.         case 11:    /* top-center justified text */
  537.             textstyle(elt->e_brush, elt->e_size, output);
  538.             textpoint(elt->e_ptcnt, elt->e_points, output);
  539.             textadjust(elt->e_text, TOP, CENTER, output);
  540.             break;
  541.         case 12:    /* top-right justified text */
  542.             textstyle(elt->e_brush, elt->e_size, output);
  543.             textpoint(elt->e_ptcnt, elt->e_points, output);
  544.             textadjust(elt->e_text, TOP, RIGHT, output);
  545.             break;
  546.         case 13:    /* left-center justified text */
  547.             textstyle(elt->e_brush, elt->e_size, output);
  548.             textpoint(elt->e_ptcnt, elt->e_points, output);
  549.             textadjust(elt->e_text, CENTER, LEFT, output);
  550.             break;
  551.         case 14:    /* right-center justified text */
  552.             textstyle(elt->e_brush, elt->e_size, output);
  553.             textpoint(elt->e_ptcnt, elt->e_points, output);
  554.             textadjust(elt->e_text, CENTER, RIGHT, output);
  555.             break;
  556.         case 15:    /* bottom-center justified text */
  557.             textstyle(elt->e_brush, elt->e_size, output);
  558.             textpoint(elt->e_ptcnt, elt->e_points, output);
  559.             textadjust(elt->e_text, BOTTOM, CENTER, output);
  560.             break;
  561.         }
  562.         if (elt->e_what > 15) {
  563.             error("Bad element type %d; ignored.", elt->e_what);
  564.         }
  565.     }
  566.     for (elt = elt_list; elt < elend; elt++) {
  567.         /* handle this picture element now */
  568.         putc('\n', output);
  569.         switch (elt->e_what) {
  570.         case 3:        /* vector */
  571.             if (elt->e_ptcnt < 2) {
  572.                 error("Need at least two points in a vector.");
  573.                 break;
  574.             }
  575.             linestyle(elt->e_brush, elt->e_size, output);
  576.             ptp = point_list;
  577.             makevector(elt->e_ptcnt, elt->e_points, output);
  578.             break;
  579.         case 4:        /* arc */
  580.             if (elt->e_ptcnt < 2) {
  581.                 error("Need at least two points for an arc!");
  582.                 return (1);
  583.             }
  584.             linestyle(elt->e_brush, elt->e_size, output);
  585.             makearc(elt->e_ptcnt, elt->e_points, output);
  586.             break;
  587.         case 5:        /* curve */
  588.             if (elt->e_ptcnt < 3) {
  589.                 error("Need at least three points for curve.");
  590.                 return (1);
  591.             }
  592.             linestyle(elt->e_brush, elt->e_size, output);
  593.             makecurve(elt->e_ptcnt, elt->e_points, output);
  594.             break;
  595.         case 7:        /* b-spline curve */
  596.             if (elt->e_ptcnt < 2) {
  597.                 error(
  598.                         "Can't draw B-spline with fewer than two points.");
  599.                 return (1);
  600.             }
  601.             linestyle(elt->e_brush, elt->e_size, output);
  602.             makebspline(elt->e_ptcnt, elt->e_points, output);
  603.             break;
  604.         case 8:        /* bezier spline curve */
  605.             if (elt->e_ptcnt < 3) {
  606.                 error(
  607.                         "Can't draw Bezier with fewer than two points.");
  608.                 return (1);
  609.             }
  610.             linestyle(elt->e_brush, elt->e_size, output);
  611.             makebezier(elt->e_ptcnt, elt->e_points, output);
  612.             break;
  613.         }
  614.         if (elt->e_what > 15) {
  615.             error("Bad element type %d; ignored.", elt->e_what);
  616.         }
  617.     }
  618.  
  619.     /* terminate the page description with trailer */
  620.     fprintf(output, "\n%%%%Trailer\n");
  621.     fprintf(output, "grestore\n");
  622.  
  623.     return (0);
  624. }
  625.  
  626. findbbox(elt)
  627.     struct element    *elt;
  628. {
  629.     struct point    *ptp, *end;
  630.     double        minx, maxx, miny, maxy;
  631.  
  632.     /* initialize bounding box values */
  633.     minx = miny = LARGE;
  634.     maxx = maxy = -LARGE;
  635.  
  636.     end = elt->e_points + elt->e_ptcnt;
  637.     for (ptp = elt->e_points; ptp < end; ptp++) {
  638.         if (ptp->p_x < minx)
  639.             minx = ptp->p_x;
  640.         if (ptp->p_x > maxx)
  641.             maxx = ptp->p_x;
  642.         if (ptp->p_y < miny)
  643.             miny = ptp->p_y;
  644.         if (ptp->p_y > maxy)
  645.             maxy = ptp->p_y;
  646.     }
  647.  
  648.     /* make sure we have a reaonable bounding box */
  649.     if (minx > maxx || miny > maxy)
  650.         minx = maxx = miny = maxy = 0.0;
  651.  
  652.     /* set them in the element and return */
  653.     elt->e_llx = minx;
  654.     elt->e_lly = miny;
  655.     elt->e_urx = maxx;
  656.     elt->e_ury = maxy;
  657.     return (0);
  658. }
  659.  
  660. scale(elt, xscale, yscale)
  661.     struct element    *elt;
  662.     double    xscale, yscale;
  663. {
  664.     struct point    *ptp, *end;
  665.  
  666.     end = elt->e_points + elt->e_ptcnt;
  667.     for (ptp = elt->e_points; ptp < end; ptp++) {
  668.         ptp->p_x *= xscale;
  669.         ptp->p_y *= yscale;
  670.     }
  671.     /* find bounding box now that it's changed */
  672.     return findbbox(elt);
  673. }
  674.  
  675. translate(elt, xtrans, ytrans)
  676.     struct element    *elt;
  677.     double    xtrans, ytrans;
  678. {
  679.     struct point    *ptp, *end;
  680.  
  681.     end = elt->e_points + elt->e_ptcnt;
  682.     for (ptp = elt->e_points; ptp < end; ptp++) {
  683.         ptp->p_x += xtrans;
  684.         ptp->p_y += ytrans;
  685.     }
  686.  
  687.     /* adjust bounding box by translation */
  688.     elt->e_llx += xtrans;
  689.     elt->e_lly += ytrans;
  690.     elt->e_urx += xtrans;
  691.     elt->e_ury += ytrans;
  692.     return (0);
  693. }
  694.  
  695. double    curgray = 0.0;
  696. int    dashset = 0;
  697. double    curwidth = -1.0;
  698.  
  699. #define THINWIDTH    0.3
  700. #define MEDWIDTH    0.8
  701. #define THICKWIDTH    1.4
  702.  
  703. linestyle(brush, size, output)
  704.     FILE    *output;
  705. {
  706.     /* set up line style (or brush) approriately */
  707.     switch (brush) {
  708.     case 1:        /* thin dotted lines */
  709.         fputs("[1.0 1.6] 0 setdash\n", output);
  710.         dashset = 1;
  711.         if (curwidth != THINWIDTH) {
  712.             curwidth = THINWIDTH;
  713.             fprintf(output, "%lg setlinewidth\n", curwidth);
  714.         }
  715.         break;
  716.     case 2:        /* thin dot-dashed lines */
  717.         fputs("[1.0 1.6 3.5 1.6] 0 setdash ", output);
  718.         dashset = 1;
  719.         if (curwidth != THINWIDTH) {
  720.             curwidth = THINWIDTH;
  721.             fprintf(output, "%lg setlinewidth\n", curwidth);
  722.         }
  723.         break;
  724.     case 3:        /* thick solid lines */
  725.         if (dashset) {
  726.             fputs("[] 0 setdash ", output);
  727.             dashset = 0;
  728.         }
  729.         if (curwidth != THICKWIDTH) {
  730.             curwidth = THICKWIDTH;
  731.             fprintf(output, "%lg setlinewidth\n", curwidth);
  732.         }
  733.         break;
  734.     case 4:        /* thin dashed lines */
  735.         fputs("[3.5 3.0] 0 setdash ", output);
  736.         dashset = 1;
  737.         if (curwidth != THINWIDTH) {
  738.             curwidth = THINWIDTH;
  739.             fprintf(output, "%lg setlinewidth\n", curwidth);
  740.         }
  741.         break;
  742.     case 5:        /* thin solid lines */
  743.         if (dashset) {
  744.             fputs("[] 0 setdash ", output);
  745.             dashset = 0;
  746.         }
  747.         if (curwidth != THINWIDTH) {
  748.             curwidth = THINWIDTH;
  749.             fprintf(output, "%lg setlinewidth\n", curwidth);
  750.         }
  751.         break;
  752.     case 6:        /* medium solid lines */
  753.         if (dashset) {
  754.             fputs("[] 0 setdash ", output);
  755.             dashset = 0;
  756.         }
  757.         if (curwidth != MEDWIDTH) {
  758.             curwidth = MEDWIDTH;
  759.             fprintf(output, "%lg setlinewidth\n", curwidth);
  760.         }
  761.         break;
  762.     default:    /* bad brush type */
  763.         error("Bad brush type %d specified; ignored.", brush);
  764.         return (1);
  765.     }
  766.  
  767.     /* lines are always drawn full strength */
  768.     if (curgray != 0.0) {
  769.         curgray = 0.0;
  770.         fprintf(output, "%lg setgray\n", curgray);
  771.     }
  772.  
  773.     /* size is ignored for vectors, arcs and curves */
  774.  
  775.     return (0);
  776. }
  777.  
  778. #define BLACK    16
  779. #define WHITE    1
  780.  
  781. polystyle(brush, size, output)
  782.     FILE    *output;
  783. {
  784.     double    level, steps;
  785.  
  786.     /* ignore outline style (or brush) here */
  787.  
  788.     /* size is stipple pattern index */
  789.     if (size > BLACK)
  790.         size = BLACK;
  791.     if (size < WHITE)
  792.         size = WHITE;
  793.     steps = 100.0 / (double)BLACK;
  794.     level = 100.0 - (steps * (size - 1));
  795.     if (level != curgray) {
  796.         fprintf(output, "%lg setgray\n", level / 100.0);
  797.         curgray = level;
  798.     }
  799.  
  800.     return (0);
  801. }
  802.  
  803. textpoint(count, list, output)
  804.     struct point    *list;
  805.     FILE        *output;
  806. {
  807.     double        x, y;
  808.     register int    i;
  809.  
  810.     if (count < 1) {
  811.         error("Need at least one point for text items!");
  812.         return (-1);
  813.     }
  814. #ifdef STUPID
  815.     x = y = 0.0;
  816.     for (i = 0; i < count; i++) {
  817.         x += list[i].p_x;
  818.         y += list[i].p_y;
  819.     }
  820.     x = x / (double)count;
  821.     y = y / (double)count;
  822. #else !STUPID
  823.     x = list[0].p_x;
  824.     y = list[0].p_y;
  825. #endif STUPID
  826.     
  827.     fprintf(output, "%lg %lg moveto\n", x, y);
  828.     return(0);
  829. }
  830.  
  831. char    *curfont = NULL;
  832. int    cursize = -1;
  833.  
  834. textstyle(brush, size, output)
  835.     FILE    *output;
  836. {
  837.     char    *fname;
  838.     int    fsize;
  839.  
  840.     /* set the font face from brush */
  841.     switch (brush) {
  842.     default:    /* unknown face */
  843.         error("Bad font number %d in entry; using Roman.", brush);
  844.         /* fall through ... */
  845.     case 1:        /* roman */
  846.         fname = R_fontname;
  847.         break;
  848.     case 2:        /* italics */
  849.         fname = I_fontname;
  850.         break;
  851.     case 3:        /* bold */
  852.         fname = B_fontname;
  853.         break;
  854.     case 4:        /* special */
  855.         fname = S_fontname;
  856.         break;
  857.     }
  858.  
  859.     /* set point size from the size entry */
  860.     switch (size) {
  861.     case 1:        /* 8 point */
  862.         fsize = 8;
  863.         break;
  864.     case 2:        /* 12 point */
  865.         fsize = 12;
  866.         break;
  867.     case 3:        /* 18 point */
  868.         fsize = 18;
  869.         break;
  870.     case 4:        /* 28 point */
  871.         fsize = 28;
  872.         break;
  873.     default:
  874.         error("Bad font size %d; using eight point.", size);
  875.         fsize = 8;
  876.         break;
  877.     }
  878.  
  879.     /* text is always printed full strength */
  880.     if (curgray != 0.0) {
  881.         fputs("0 setgray\n", output);
  882.         curgray = 0.0;
  883.     }
  884.  
  885.     /* get font at given size if not already done */
  886.     if (fname != curfont || fsize != cursize) {
  887.         fprintf(output,
  888.             "/%s findfont %d scalefont setfont\n", fname, fsize);
  889.         curfont = fname;
  890.         cursize = fsize;
  891.     }
  892.  
  893.     return (0);
  894. }
  895.  
  896. textadjust(text, vert, hor, output)
  897.     char    *text;
  898.     FILE    *output;
  899. {
  900.     char        sbuf[BUFSIZ], *send = sbuf + sizeof (sbuf) - 1;
  901.     register char    *tp, *sp;
  902.     double        vmove;
  903.  
  904.     if (text == NULL || *text == '\0') {
  905.         error("Null text string to show!");
  906.         return (-1);
  907.     }
  908.     tp = text;
  909.     sp = sbuf;
  910.     while (*tp != '\0' && sp < send) {
  911.         switch (*tp) {
  912.         case '(':
  913.         case ')':
  914.         case '\\':
  915.             *sp++ = '\\';
  916.             *sp++ = *tp++;
  917.             break;
  918.         default:
  919.             *sp++ = *tp++;
  920.             break;
  921.         }
  922.     }
  923.     *sp = '\0';
  924.  
  925.     /* make adjustment movements, we try to do this optimally ... */
  926.     switch (vert) {
  927.     case BOTTOM:
  928.         vmove = 1.0;
  929.         break;
  930.     case CENTER:
  931.         vmove = 1.0 - (double)cursize / 2.0;
  932.         break;
  933.     case TOP:
  934.         vmove = 1.0 - (double)cursize;
  935.         break;
  936.     }
  937.  
  938.     switch (hor) {
  939.     case LEFT:
  940.         if (vmove != 0.0)
  941.             fprintf(output, "0 %lg rmoveto ", vmove);
  942.         fprintf(output, "(%s) show\n", sbuf);
  943.         break;
  944.     case CENTER:
  945.         fprintf(output,
  946.         "(%s) dup stringwidth pop 2.0 div -1 mul %lg rmoveto show\n",
  947.             sbuf, vmove);
  948.         break;
  949.     case RIGHT:
  950.         fprintf(output,
  951.             "(%s) dup stringwidth pop -1 mul %lg rmoveto show\n",
  952.             sbuf, vmove);
  953.         break;
  954.     }
  955.  
  956.     return (0);
  957. }
  958.  
  959. makevector(count, list, output)
  960.     struct point    *list;
  961.     FILE        *output;
  962. {
  963.     struct point    *ptp, *ptend;
  964.  
  965.     if (list == NULL || count < 2)
  966.         return (1);
  967.  
  968.     ptend = list + count;
  969.     ptp = list;
  970.  
  971.     fprintf(output, "newpath\n    %lg %lg moveto\n",
  972.         ptp->p_x, ptp->p_y);
  973.     for (++ptp; ptp < ptend; ptp++)
  974.         fprintf(output, "    %lg %lg lineto\n",
  975.             ptp->p_x, ptp->p_y);
  976.     fputs("stroke\n", output);
  977.  
  978.     return (0);
  979. }
  980.  
  981. makepolygon(count, list, output, brush, size)
  982.     struct point    *list;
  983.     FILE        *output;
  984. {
  985.     struct point    *ptp, *ptend;
  986.  
  987.     if (list == NULL || count < 3)
  988.         return (1);
  989.  
  990.     ptp = list;
  991.     ptend = list + count;
  992.  
  993.     /* output the filled region now */
  994.     fprintf(output, "newpath\n    %lg %lg moveto\n",
  995.         ptp->p_x, ptp->p_y);
  996.     for (++ptp; ptp < ptend; ptp++) {
  997.         fprintf(output, "    %lg %lg lineto\n",
  998.             ptp->p_x, ptp->p_y);
  999.     }
  1000.     fputs("closepath fill\n", output);
  1001.  
  1002.     /* draw the outline now, unless brush is zero */
  1003.     if (brush > 0) {
  1004.         linestyle(brush, size, output);
  1005.         ptp = list;
  1006.         fprintf(output, "newpath\n    %lg %lg moveto\n",
  1007.             ptp->p_x, ptp->p_y);
  1008.         for (++ptp; ptp < ptend; ptp++)
  1009.             fprintf(output, "    %lg %lg lineto\n",
  1010.                 ptp->p_x, ptp->p_y);
  1011.         fputs("closepath stroke\n", output);
  1012.     }
  1013.  
  1014.     return (0);
  1015. }
  1016.  
  1017. #define sqr(x)    ((x) * (x))
  1018. #define TWOPI    (2.0 * 3.1415927)
  1019.  
  1020. makearc(count, list, output)
  1021.     struct point    *list;
  1022.     FILE        *output;
  1023. {
  1024.     double    ang1, ang2, radius;
  1025.     double    dx, dy;
  1026.  
  1027.     /* get radius from center of curvature and a point */
  1028.     radius = hypot(list[0].p_x - list[1].p_x, list[0].p_y - list[1].p_y);
  1029.  
  1030.     fputs("newpath ", output);
  1031.     if (count == 2 || count == 6 ||
  1032.         (list[1].p_x == list[2].p_x && list[1].p_y == list[2].p_y)) {
  1033.         /* drawing a circle, don't need angles */
  1034.         fprintf(output, "%lg %lg %lg 0 360 arc",
  1035.             list[0].p_x, list[0].p_y, radius);
  1036.     } else {
  1037.         /* drawing an arc, find two angles */
  1038.                 dx = list[1].p_x - list[0].p_x;
  1039.                 dy = list[1].p_y - list[0].p_y;
  1040.                 ang1 = atan2(dy, dx) / TWOPI * 360.0;
  1041.                 dx = list[2].p_x - list[0].p_x;
  1042.                 dy = list[2].p_y - list[0].p_y;
  1043.                 ang2 = atan2(dy, dx) / TWOPI * 360.0;
  1044.         /* output proper PostScript code */
  1045.         fprintf(output, "%lg %lg %lg %lg %lg arc",
  1046.             list[0].p_x, list[0].p_y, radius, ang1, ang2);
  1047.     }
  1048.     fputs(" stroke\n", output);
  1049.  
  1050.     return (0);
  1051. }
  1052.  
  1053. error(va_alist)
  1054.     va_dcl
  1055. {
  1056.     char *format;
  1057.     va_list args;
  1058.  
  1059.     va_start(args);
  1060.     format = va_arg(args, char *);
  1061.  
  1062.     fprintf(stderr, "%s: \"%s\", %d: ", program, errfile, errline);
  1063.     vfprintf(stderr, format, args);
  1064.     putc('\n', stderr);
  1065. }
  1066.  
  1067. char *
  1068. savestr(str)
  1069.     char    *str;
  1070. {
  1071.     extern char    *malloc();
  1072.     char        *ptr;
  1073.     int        len;
  1074.  
  1075.     if (*str == NULL || (len = strlen(str)) < 1)
  1076.         return (NULL);
  1077.     if ((ptr = malloc(len + 1)) == NULL) {
  1078.         fprintf(stderr, "%s: Not enough memory for %d char. string!\n",
  1079.             program, len);
  1080.         exit(1);
  1081.     }
  1082.     strcpy(ptr, str);
  1083.     return (ptr);
  1084. }
  1085.